#ifndef _GS_OBJECT_H_
#define _GS_OBJECT_H_
/*******************************************************************************
 ** Name: object.h                                                            **
 ** Description:                                                              **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved 2-clause BSD License                **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  Redistribution and use in source and binary forms, with or without       **
 **  modification, are permitted provided that the following conditions are   **
 **  met:                                                                     **
 **                                                                           **
 **  * Redistributions of source code must retain the above copyright notice, **
 **    this list of conditions and the following disclaimer.                  **
 **  * Redistributions in binary form must reproduce the above copyright      **
 **    notice, this list of conditions and the following disclaimer in the    **
 **    documentation and/or other materials provided with the distribution.   **
 **                                                                           **
 **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS      **
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED **
 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           **
 ** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT        **
 ** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
 **                                                                           **
 ******************************************************************************/
// Modified $Date: 2011-10-22 02:09:07 +0000 (Sat, 22 Oct 2011) $ by $Author: gian.james $
#define _object_h_ID    "$Id: object.hpp 146 2011-10-22 02:09:07Z gian.james $"

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <stdarg.h>
#include <string>
#include <map>
#include <list>
#include "common.hpp"
#include "visitor.hpp"

#define OBJECT_UNKNOWN     "<unknown>"
#define OBJECT_MAX_STACK	20

// TODO This needs to be replaced with something more manageable
enum class OType
{
    Unknown, Character, NPC, Door, Container, RangedWeapon, MeleeWeapon, 
    Item, Misc, Spell, Herb, Poltice, Potion, Area, Setting, Kit, Ammo,
    Agency, Weapon, Trash, Room, Scratch, Client, Trap, Electronic, Computer,
    Craftable,
    max
};

enum class TierGrade
{
	I, II, III, IV, V, VI, VII, VIII, IX, X
};


// Object flags
#define OBJECT_MOVEABLE		0x01
#define OBJECT_PLOT_CRIT	0x02
#define OBJECT_STACKABLE	0x04
#define OBJECT_WEARABLE		0x08
#define OBJECT_WIELDABLE	0x10
#define OBJECT_SELLABLE		0x20
#define OBJECT_IS_CRAFTED	0x40

//class Character;
//! @class WorldObject
//! @brief The base class for all instantiated objects in the world
#pragma db abstract
class WorldObject : public Pattern::VisitorAcceptor
{
public:
    //constructor and destructor
    WorldObject(void);
    WorldObject(OType t,std::string n);
    virtual ~WorldObject(void);

    entity_t   ID() const { return id; }
    std::string & Name() { return name; }
    virtual const std::string& Desc() const { return desc; }
    virtual std::string& Desc() { return desc; }
    std::string & 	Terse() { return terse; }
    virtual OType    Type(OType t = OType::Unknown) 
        { if (t == OType::Unknown) otype = t; return otype; }
    ushort  &    Weight() { return weight; }
	std::string	UUID2String(boost::uuids::uuid u) { return boost::uuids::to_string(u); }
	boost::uuids::uuid  StringToUUID(const std::string & s);
	std::string &	UUID() const { return uuid; }
    virtual std::string TypeToStr() { return "base::WorldObject"; };
    const std::list<std::string> & Adjectives() const { return adj; }
    std::list<std::string> & AKA() { return aka; }
    void			AddAdjectives(const std::string &s) { adj.push_back(s); }
    bool			IsAdjective(const std::string &);
    void			AddAttribute(const std::string &a,const std::string &v)
    				{ attr[a] = v; }
    std::string &	GetAttribute(const std::string & a) { return attr[a]; }
    const std::string & 	Tag() const { return tag; }
    std::string &	Tag() { return tag; }
    int		&		Slots() { return slots; }
    flags8	&		Flags() { return flags; }
    void			SetFlag(int f) { BMSET(flags,f); }
    void			ClearFlag(int f) { BMCLR(flags,f); }
    TierGrade &			Tier() { return tier; }
    entity_t &		CarriedBy() { return carriedBy; }
    ushort &		Complexity() { return complexity; }
    entity_t &		CraftedBy() { return craftedBy; }
    ushort &		DetectDC() { return detectDC; }
    ushort &		DisableDC() { return disableDC; }
    ushort &		DmgSave() { return dmgSave; }
    ushort &		CurrentDurability() { return durabilityCurr; }
    double &		DurabilityDecay() { return durabilityDecay; }
    ushort &		MaxDurability() { return durabilityMax; }
    ushort &		X() { return x; }
    ushort &		Y() { return y; }
    ushort &		XPReward() { return xpReward; }
    ushort &		PR() { return powerRating; }
    ushort &		StackAmount() { return stackAmount; }
    bool			Stackable() { return stackAmount ? true:false; }
    // Objects should be able to perform commands on themselves.  Each
    // derived object must implement these functions themselves.

    //void    AddObjRef(const std::string w);
    //bool    AKA(const std::string w);

    // Commands over the object
    // TODO revisit this mechanism
    virtual int		Command(std::string cmd, std::string player) { return 0; }
    virtual int		accept(Pattern::Visitor * v) { return 0; }

protected:
    std::string    name;       //!< Object name
    std::string    desc;       //!< Object description (full version)
    std::string		terse;		//!< terse/brief/short version of description
    OType           otype;      //!< Object base type
	#pragma db id auto
    entity_t          id;         //!< Unique ID
    ushort             weight;     //!< uuum...
    std::list<std::string>       aka;        //!< other names for this object
    std::string		tag;		//!< easier reference than remembering oid
	std::string 	uuid;		//!< the UUID of this object
	std::list<std::string> adj;	//!< any adjectives applied to this object
	//! all world objects may have any number of arbitrary attributes added
	//! at runtime and this supports that notion.
	std::map<std::string,std::string> attr;
	int				slots;		//!< if container-able, how many slots it takes up
	flags8			flags;		//!< object flags
#pragma db column("carried_by")
	entity_t		carriedBy;	//!< who's carrying this obj? is this necessary?
#pragma db column("crafted_by")
	entity_t		craftedBy;	//! who crafted this item?
	TierGrade			tier;		//! Accessibility tier
#pragma db column("in_room")
	bool			inRoom;		//! is this in a room? if so loc = carriedBy
	ushort			x;			//! inside room coordinates
	ushort			y;			//! inside room coordinates
	entity_t			size;		//! id from size in DB
#pragma db column("power_rating")
	ushort			powerRating; //! does the object have a power rating?
#pragma db column("dmg_save")
	ushort			dmgSave;
#pragma db column("detect_dc")
	ushort			detectDC;	//! DC against passive notice skill check
#pragma db column("disable_dc")
	ushort			disableDC;
	ushort			complexity;	//! used as dc for modify, repair, upgrade, disable
#pragma db column("xp_reward")
	ushort			xpReward;			//! any xp for actions against this object
#pragma db column("durability_max")
	ushort			durabilityMax;
#pragma db column("durability_curr")
	ushort			durabilityCurr;
#pragma db column("durability_decay")
	double			durabilityDecay;
#pragma db column("stack_amount")
	ushort			stackAmount;	//! if stackable, how many in stack?
};


// Utility functions for use by STL algorithms 'n such
bool operator < (const WorldObject  a, const WorldObject  b);
bool operator == (const WorldObject  a, const WorldObject  b);


#endif 	/* _GS_OBJECT_H_ */
